﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Domain.Repositories;
using Abp.Runtime.Caching;
using KelonProud.Administration.Domain.Authorization;
using KelonProud.Linq;


namespace KelonProud.Administration.Managers.Authorization
{
   public class NavigationManager:KelonProudDomainService<Navigation>
   {
       private readonly IRepository<EditionNavigation> _editonNavgationRepository;
       private readonly IRepository<NavigationRole> _navRoleRepository;
       private readonly ICacheManager _cacheManager;

        public NavigationManager(
            IRepository<Navigation, int> manageRepository, 
            IRepository<EditionNavigation> editonNavgationRepository,
            ICacheManager cacheManager, IRepository<NavigationRole> navRoleRepository) : base(manageRepository)
        {
            _editonNavgationRepository = editonNavgationRepository;
            _cacheManager = cacheManager;
            _navRoleRepository = navRoleRepository;
        }

       public IEnumerable<Navigation> CachList
       {
           get
           {
               return base.List;
               //return _cacheManager.GetCache("systemCache")
               //    .Get("navgation", () =>base.List);
           }
       }

       public override IQueryable<Navigation> Query  => base.Query.Where(
           w => w.TenantId == null || w.TenantId == AbpSession.TenantId);

       public override List<Navigation> List => CachList.Where(
           w => w.TenantId == null || w.TenantId == AbpSession.TenantId).ToList();

       public Navigation GetNavigationByCode(string code)
       {
           return CachList.FirstOrDefault(f => f.Code == code);
       }

        public Task<IEnumerable<Navigation>> GetNavigationsByParentIdAsync(int? parentId)
       {
           var parentIdPath = "-{0}-".FormatWith(parentId);
           return Task.FromResult(List.Where(w => parentId != null && w.IdPath.Contains(parentIdPath)|| parentId==null));
       }

       public List<Navigation> GetNavigationsByParentId(int? parentId)
       {
           var parentIdPath = "-{0}-".FormatWith(parentId);
           return List.Where(w => parentId != null && w.IdPath.Contains(parentIdPath) || parentId == null).ToList();
       }

       public int SaveNavigation(Navigation navigation)
       {
           CheckNavigationExits(navigation);

           var result = ManagerRepository.InsertOrUpdateAndGetId(navigation);
            UnitOfWorkManager.Current.SaveChanges();
            _cacheManager.GetCache("systemCache").Set("navgation", base.Query);

           return result;
       }

       public Task<int> SaveNavigationAsync(Navigation navigation)
       {
           CheckNavigationExits(navigation);

           var result = ManagerRepository.InsertOrUpdateAndGetIdAsync(navigation);
            CurrentUnitOfWork.SaveChanges();
           _cacheManager.GetCache("systemCache").SetAsync("navgation", base.List);

           return result;
       }

       public void SetRoles(Navigation navigation, string[] roleIds)
       {
            if(navigation.Roles==null)
                navigation.Roles = new List<NavigationRole>();

           foreach (var navRole in navigation.Roles.ToList())
           {
               if (roleIds.All(roleId => roleId != navRole.RoleId.ToString()))
               {
                   _navRoleRepository.Delete(navRole);
               }
           }

           //Add to added roles
           foreach (var roleId in roleIds)
           {
               var all = navigation.Roles.All(ur => ur.RoleId != roleId.ToInt32(0));
               if (all)
               {
                   _navRoleRepository.Insert(new NavigationRole()
                   {
                       NavigationId = navigation.Id,
                       RoleId = roleId.ToInt32(0)
                   });
               }
           }
       }

       public void SetEditions(Navigation navigation, string[] editionIds)
       {

           if (navigation.Editions == null)
               navigation.Editions = new List<EditionNavigation>();

           foreach (var navEdition in navigation.Editions.ToList())
           {
               if (editionIds.All(editionId => editionId != navEdition.EditionId.ToString()))
               {
                   _editonNavgationRepository.Delete(navEdition);
               }
           }

           //Add to added roles
           foreach (var editionId in editionIds)
           {
               var all = navigation.Editions.All(ur => ur.EditionId != editionId.ToInt32(0));
               if (all)
               {
                   _editonNavgationRepository.Insert(new EditionNavigation()
                   {
                       NavigationId = navigation.Id,
                       EditionId = editionId.ToInt32(0)
                   });
               }
           }
       }

       public void DeleteNavigation(Navigation nav)
       {
           if (nav != null)
               ManagerRepository.DeleteAsync(nav);
       }

       public void DeleteNavigationRole(NavigationRole navigationRole)
       {
            if(navigationRole!=null)
                _navRoleRepository.Delete(navigationRole);
       }

       public void DeleteNavigationEdtion(EditionNavigation editionNavigation)
       {
           if (editionNavigation != null)
               _editonNavgationRepository.Delete(editionNavigation);
       }

        public bool CheckNavigationActionExits(Navigation navigation)
       {
           return List.Any(w => w.Id != navigation.Id && w.ParentId == navigation.ParentId && w.Name == navigation.Name) 
                || List.Any(w => w.Id != navigation.Id && w.ParentId == navigation.ParentId && w.Code == navigation.Code);
       }

       private void CheckNavigationExits(Navigation navigation)
       {
            if(List.Any(w=>w.Id!=navigation.Id&&w.ParentId==navigation.ParentId&&w.Name==navigation.Name))
                throw  new Exception("菜单名称【{0}】在同父级菜单下已存在".FormatWith(navigation.Name));

           if (List.Any(w => w.Id != navigation.Id && w.ParentId == navigation.ParentId && w.Code == navigation.Code))
               throw new Exception("菜单编码【{0}】在同父级菜单下已存在".FormatWith(navigation.Code));
        }
   }
}
